using System.Linq.Expressions;
using EFCore.BulkExtensions;
using Gateway.Common.Entity;
using Gateway.IRepositories;
using Microsoft.EntityFrameworkCore;

namespace Gateway.Domain.EFCore;

/// <summary>
/// 
/// </summary>
/// <typeparam name="TEntity"></typeparam>
public class EFRepository<TEntity> : IAppRepository<TEntity> where TEntity : class, IEntityBase
{
    private readonly Domain.EFCore.ShareCoreDbContext _dbMaster;

    /// <summary>
    /// 
    /// </summary>
    /// <param name="dbMaster"></param>
    public EFRepository(Domain.EFCore.ShareCoreDbContext dbMaster)
    {
        _dbMaster = dbMaster;
    }

    public DbContext DbMaster => _dbMaster;

    public IQueryable<TEntity> Table => DbMaster.Set<TEntity>().AsNoTracking(); //查询不用追踪
    
    public DbSet<TEntity> Entities
    {
        get { return DbMaster.Set<TEntity>(); }
    }

    // public abstract IQueryable<TEntity> GetAll();
    public virtual Task<TEntity> GetAsync(string id)
    {
        if (string.IsNullOrWhiteSpace(id))
        {
            return Task.FromResult(default(TEntity));
        }

        return Entities.FirstAsync(s => s.Id == id);
    }

    public virtual Task<List<TEntity>> GetListAsync(Expression<Func<TEntity, bool>> predicate)
    {
        if (predicate == null)
        {
            return Task.FromResult(default(List<TEntity>));
        }

        return Table.Where(predicate).ToListAsync();
    }
    /// <summary>
    /// 
    /// </summary>
    /// <param name="predicate"></param>
    /// <returns></returns>
    public virtual Task<TEntity> FirstOrDefaultAsync(Expression<Func<TEntity, bool>> predicate)
    {
        if (predicate == null)
        {
            return Task.FromResult(default(TEntity));
        }

        return Entities.FirstOrDefaultAsync(predicate);
    }

    public async Task<long> CountAsync(Expression<Func<TEntity, bool>> predicate)
    {
        if (predicate == null)
        {
            return 0;
        }

        return await Entities.CountAsync(predicate);
    }

    public virtual Task<bool> AnyAsync(Expression<Func<TEntity, bool>> predicate)
    {
        if (predicate == null)
        {
            return Task.FromResult(false);
        }

        return Entities.AnyAsync(predicate);
    }

    public virtual async Task AddAsync(TEntity entity)
    {
        await Entities.AddAsync(entity);
    }

    public virtual async Task AddRangeAsync(IEnumerable<TEntity> entity)
    {
        await Entities.AddRangeAsync(entity);
    }

    public virtual Task UpdateAsync(TEntity entity)
    {
        return Task.FromResult(Entities.Update(entity));
    }

    public Task UpdateRangeAsync(IEnumerable<TEntity> entity)
    {
        Entities.UpdateRange(entity);
        return Task.CompletedTask;
    }

    public virtual Task DeleteAsync(TEntity entity)
    {
        return Task.FromResult(Entities.Remove(entity));
    }

    public virtual async Task DeleteAsync(string id)
    {
        if (string.IsNullOrWhiteSpace(id))
        {
            return;
        }

        var data = await GetAsync(id);
        if (data == null)
        {
            return;
        }

        await Task.FromResult(Entities.Remove(data));
    }

    public virtual async Task DeleteAsync(Expression<Func<TEntity, bool>> predicate)
    {
        if (predicate == null)
        {
            return;
        }

        var data = await FirstOrDefaultAsync(predicate);
        if (data == null)
        {
            return;
        }

        await Task.FromResult(Entities.Remove(data));
    }

    public virtual async Task DeleteRangeAsync(Expression<Func<TEntity, bool>> predicate)
    {
        if (predicate == null)
        {
            return;
        }

        var data = await GetListAsync(predicate);
        if (data == null)
        {
            return;
        }

        Entities.RemoveRange(data);
    }


    public async Task BulkInsert(List<TEntity> entities)
    {
        // await Entities.AddRangeAsync(entities); 
        await DbMaster.BulkInsertAsync(entities, new BulkConfig() { });
    }

    public async Task BulkUpdate(List<TEntity> entities)
    {
        await DbMaster.BulkUpdateAsync(entities, new BulkConfig() { });
    }
}